<!-- 绘图层 -->
<template>
  <!-- js-deselect-element 用于取消选择 -->
  <div class="canvas-container" :class="jsDeselectElementClassName">
    <!-- 主体显示区域 js-design-canvas 用于生成图片时作为选择器-->
    <div
      ref="js-design-canvas"
      class="capture js-design-canvas"
      :class="{ 'preview': isPreview }"
      :style="canvasStyle"
    >
      <!-- 背景层 -->
      <canvas-background :layouts="canvas" :deselectElement="'.' + jsDeselectElementClassName"></canvas-background>
      <!-- 展示元素层 -->
      <draggable-resizable
        v-for="(item, index) of elements"
        :key="item.id"
        :ref="'ref-element-' + item.id"
        :handles="item.type === typeConstants.IMAGE ? ['tl','tr','br','bl'] : ['tl','tr','mr','br','bl','ml']"
        :w="item.width"
        :h="item.height"
        :x="item.x"
        :y="item.y"
        :r="item.rotate"
        :z="item.zIndex"
        :scale="canvas.scale"
        :draggable="!item.lock && !isPreview && item.draggable"
        :resizable="!item.lock && !isPreview"
        :min-width="30"
        :lock-aspect-ratio="item.type === 'image'"
        snap
        :deselectElement="'.' + jsDeselectElementClassName"
        @on-line-params="getRefLineParams"
        @resizing="onResize"
        @on-rotate="onRotate"
        @dragging="onDrag"
        @activated="onActivated(item, index)"
        @deactivated="onDeactivated(item, index)"
      >
        <canvas-font v-if="item.type === typeConstants.FONT" :params="item" :index="index" :disabled="isPreview"></canvas-font>
      </draggable-resizable>
      <!-- 辅助线: 用于多图像对齐用 -->
      <span
        v-for="(item, index) of vLine"
        :key="'v-' + index"
        v-show="item.display"
        class="ref-line v-line"
        :style="{left: item.position, top: item.origin, height: item.lineLength}"
      />
      <span
        v-for="(item, index) of hLine"
        :key="'h-' + index"
        v-show="item.display"
        class="ref-line h-line"
        :style="{left: item.position, top: item.origin, width: item.lineLength}"
      />
    </div>
    <!-- 缩放工具 -->
    <!-- 缩放面板 -->
  </div>
</template>

<script>
import { CanvasBackground, CanvasFont } from './components'
import DraggableResizable from './components/draggable-resizable'
import { mapState } from 'vuex'
import { STORE_NAMESPACE, typeConstants } from '../../config'
export default {
  name: 'DesignCanvas',
  components: {
    CanvasBackground,
    CanvasFont,
    DraggableResizable
  },
  data () {
    return {
      typeConstants: { ...typeConstants }, // 元素类型, 这里直接使用会因为Sysbol类型不生效, 使用解构转为普通对象
      jsDeselectElementClassName: 'js-deselect-element', // 取消选择的class选择器
      offset: {
        left: 0,
        top: 0,
        offsetWidth: 0,
        offsetHeight: 0
      },
      isPreview: false, // 是否为预览
      vLine: [], // 辅助线
      hLine: [] // 辅助线
    }
  },
  computed: {
    ...mapState({
      layouts: state => state[STORE_NAMESPACE].layouts,
      editor: state => state[STORE_NAMESPACE].currentEditor,
      current: state => state[STORE_NAMESPACE].current,
      currentIndex: state => state[STORE_NAMESPACE].currentIndex
    }),
    canvas () { // 当前画布
      return this.layouts
    },
    // 元素集合
    elements () {
      return this.canvas.elements
    },
    // 画布宽度, 便于计算偏移量
    width () {
      return this.canvas.width
    },
    height () { // 同上
      return this.canvas.height
    },
    // 画布样式
    canvasStyle () {
      return {
        'left': `${this.offset.left}px`,
        'top': `${this.offset.top}px`,
        'transform': `scale(${this.canvas.scale})`, // default 1
        'width': `${this.width}px`, // default 960
        'height': `${this.height}px` // default 540
      }
    }
  },
  created () {
    // 这里是功能的开始, 画布的初始化
    // this.onBusCreatedCanvas() // 这里首次加载的时候, 并没有画布, 直接调用会报错, 采用bus总线来监听
    this.$bus.on('bus-design-created-canvas', this.onBusCreatedCanvas)
    // 设置监听获取图层组件并回调
    this.$bus.on('bus-design-element-event', this.onBusElementEvent)
  },
  beforeDestroy () {
    this.$bus.off('bus-design-created-canvas', this.onBusCreatedCanvas)
    this.$bus.off('bus-design-element-event', this.onBusElementEvent)
  },
  methods: {
    // id 是元素id, callback是组件的方法
    onBusElementEvent ({id, callback}) {
      if (callback) {
        // 找到ref给回调函数
        const refs = this.$refs[`ref-element-${id}`]
        if (Object.prototype.toString.call(refs) === '[object Object]') {
          refs && callback(refs)
        } else {
          refs && callback(refs[0])
        }
      }
    },
    // 重置, 初始化, 切换画布
    onBusCreatedCanvas () {
      // 位置重置
      this.setOffset()
      // 适应屏幕
      this.$nextTick(() => {
        // todo 重置缩放
      })
    },
    // 重置画布位置信息
    setOffset () {
      const { offsetWidth, offsetHeight } = this.$el
      const left = (offsetWidth - this.width) / 2 // 设置左偏移
      const top = (offsetHeight - this.height) / 2 // 设置上偏移
      this.offset = {
        offsetWidth,
        offsetHeight,
        left,
        top
      }
    },
    // 设置当前选中模块
    setCurrent (current) {
      this.$store.dispatch(`${STORE_NAMESPACE}/setCurrent`, current)
      // 更新当前选中模块
      this.$store.dispatch(`${STORE_NAMESPACE}/setElement`, {
        index: this.currentIndex,
        value: current
      })
    },
    // 获取辅助线的位置的回调事件
    getRefLineParams (params) {
      const { vLine, hLine } = params
      this.vLine = vLine
      this.hLine = hLine
    },
    // 拖动中
    onDrag (x, y) {
      const current = {
        ...this.current,
        x,
        y
      }
      this.setCurrent(current)
    },
    // 旋转
    onRotate (rotate) {
      const current = {
        ...this.current,
        rotate
      }
      this.setCurrent(current)
    },
    // 调整大小
    onResize (x, y, width, height) {
      const current = {
        ...this.current,
        x,
        y,
        width,
        height
      }
      this.setCurrent(current)
      this.editor && this.getEditorInfo()
    },
    // 更新编辑器信息
    getEditorInfo () {
      const { clientWidth, clientHeight } = this.editor.root
      const current = {
        ...this.current,
        width: clientWidth + 1, // ? 这里为什么要+1?
        height: clientHeight + 1
      }
      this.setCurrent(current)
    },
    onActivated (item, index) {
      if (item.type !== typeConstants.FONT) { // 这里其实应该是取消激活时去掉编辑器，取巧的是: 取消一个组件同时会开放一个组件, 如果开放的组件不是文本那么编辑器就可以清空
        this.$store.dispatch(`${STORE_NAMESPACE}/setCurrentEditor`, null)
      }
      this.$store.dispatch(`${STORE_NAMESPACE}/setCurrent`, item)
      this.$store.dispatch(`${STORE_NAMESPACE}/setCurrentIndex`, index)
    },
    onDeactivated () {
      this.$store.dispatch(`${STORE_NAMESPACE}/setCurrent`, null)
      this.$store.dispatch(`${STORE_NAMESPACE}/setCurrentIndex`, null)
    }
  }
}
</script>

<style lang="less" scoped>
.canvas-container {
  flex: 1;
  position: relative;
  .capture {
    overflow: hidden;
    position: absolute;
    box-shadow: 1px 1px 15px rgba(0, 0, 0, .2);
    background-color: #fff;
    background-image: linear-gradient(to top right, #ccc 25%, transparent 0, transparent 75%, #ccc 0, #ccc);
    &.preview {
      & ::v-deep .draggable-resizable {
        &.active:before,
        &:hover:before {
          display: none;
        }
      }
    }
    .el-image {
      width: 100%;
      height: 100%
    }
    .ref-line {
      position: absolute;
      background-color: rgb(255, 0, 204);
      z-index: 9999;
      &.v-line {
        width: 1px;
      }
      &.h-line {
        height: 1px;
      }
    }
  }
}
</style>